package com.gopay.common.rcs.service.translimit.impl;

import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.proccode.ProcCodeEnum;
import com.gopay.common.domain.rcs.RcsGAcctLimitStatistics;
import com.gopay.common.domain.rcs.RcsTransLimitStatistics;
import com.gopay.common.domain.rcs.req.RcsTransLimitRequest;
import com.gopay.common.domain.rcs.res.RcsTransLimitResponse;
import com.gopay.common.domain.solution.TranLimitRes;
import com.gopay.common.exception.GopayException;
import com.gopay.common.rcs.manager.translimit.RcsBAcctLimitStatisticsManager;
import com.gopay.common.rcs.manager.translimit.RcsGAcctLimitStatisticsManager;
import com.gopay.common.rcs.service.translimit.RcsModifyTransLimitService;
import com.gopay.common.rcs.service.translimit.RcsTransLimitService;
import com.gopay.common.util.DateUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

/**
 * 交易额度校验
 * 
 * @RcsTransLimitCheckService.java
 * @author liujy
 * @2013-7-22 下午1:47:48 www.gopay.com.cn Inc.All rights reserved.
 */
@Service("rcsTransLimitBaseService")
public class RcsTransLimitBaseServiceImpl implements RcsTransLimitService {

	private Logger logger = LoggerFactory .getLogger(RcsTransLimitBaseServiceImpl.class);
    /**风控额度监控日志*/
    private Logger rcsLogger = LoggerFactory.getLogger("RCS_WARN_LOG");

	@Resource(name = "rcsGAcctLimitStatisticsManager")
	private RcsGAcctLimitStatisticsManager rcsGAcctLimitStatisticsManager;
	@Resource(name = "rcsBAcctLimitStatisticsManager")
	protected RcsBAcctLimitStatisticsManager rcsBAcctLimitStatisticsManager;
	@Resource(name = "rcsModifyTransLimitService")
	private RcsModifyTransLimitService rcsModifyTransLimitService;

	@Override
	public RcsTransLimitResponse rcsTransLimitProcess(
			RcsTransLimitRequest request) {
		String date = DateUtils.getCurrDate();
		 /**
         * modifiede by zyt 日志中明文卡号做掩码显示
         * 2017-2-14
         */
		logger.error("风控额度服务请求：" + LoggerMaskUtils.maskString(request.toString()) + "，时间：" + date);
		RcsTransLimitResponse response = checkLimit(request);
		/**
         * modifiede by zyt 日志中明文卡号做掩码显示
         * 2017-2-14
         */
		logger.error("风控额度服务请求：" + LoggerMaskUtils.maskString(request.toString()) + "，时间：" + date + "，结果：" + response);
		response.setProcCode(switchProcCode(response.getProcCode()));
		/**
         * modifiede by zyt 日志中明文卡号做掩码显示
         * 2017-2-22
         */
		logger.error("回应风控额度服务结果：" + LoggerMaskUtils.maskString(response.toString()));
		return response;
	}

	/**
	 * 
	 * @param procCode
	 * @return
	 */
	private String switchProcCode(String procCode) {
		if (StringUtils.equals(ProcCodeEnum.PROC_CODE_200W1003.getCode(), procCode)
				|| StringUtils.equals(ProcCodeEnum.PROC_CODE_200W1004.getCode(),procCode)) {
			return ProcCodeEnum.PROC_CODE_200S1000.getCode();
		}
		return procCode;
	}

	/**
	 * 
	 * @param request
	 * @return
	 */
	private RcsTransLimitResponse checkLimit(RcsTransLimitRequest request) {

		RcsTransLimitResponse response = new RcsTransLimitResponse();

		try {
			if (RcsTransLimitRequest.RequestType.check.equals(request
					.getRequestType())) {
				if (isCheck(request, response)) { // 额度校验
					checkLimit(request, response);
				}
			} else if (RcsTransLimitRequest.RequestType.checkAndAdd
					.equals(request.getRequestType())) {
				if (isCheck(request, response)) { // 额度校验
					checkLimit(request, response);
					// 增加累计额度
					addLimit(request);
				}
			} else if (RcsTransLimitRequest.RequestType.add.equals(request
					.getRequestType())) {
				// 增加累计额度
				addLimit(request);
			} else if (RcsTransLimitRequest.RequestType.subtract.equals(request
					.getRequestType())
					|| RcsTransLimitRequest.RequestType.subtract_not_times_limit
							.equals(request.getRequestType())) {
				// 回滚累计额度
				subtractLimit(request);
			}

			response.setProcCode(ProcCodeEnum.PROC_CODE_200S1000.getCode());

		} catch (GopayException e) {
			response.setProcCode(e.getErrCode());
			response.setProcCodeMsg(StringUtils.isBlank(e.getErrMsg()) ? null
					: e.getErrMsg());
			logger.error("风控额度服务异常：", e);
		} catch (Exception e) {
			response.setProcCode(ProcCodeEnum.PROC_CODE_200F1002.getCode());
			response.setProcCodeMsg(e.getMessage());
			logger.error("风控额度服务异常：", e);
		}

		return response;
	}

	/**
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	private boolean isCheck(RcsTransLimitRequest request,
			RcsTransLimitResponse response) {

		TranLimitRes conf = request.getCustTranLimitConf();

		if (null == conf) {
			logger.info("额度配置为空，不做校验，直接返回成功：" + request.getGopayOrderId());
			response.setProcCode(ProcCodeEnum.PROC_CODE_200S1000.getCode());
			return false;
		}

		boolean isEnabled = conf.isEnabled();
		if (false == isEnabled) {
			logger.info("额度配置为失效，不做校验，直接返回成功：" + request.getGopayOrderId());
			response.setProcCode(ProcCodeEnum.PROC_CODE_200W1003.getCode());
			return false;
		}

		/*String startDate = conf.getStartDate();
		String endDate = conf.getEndDate();
		String tranDate = request.getTransDate();
		if (StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)) {
			return true;
		}
		if (tranDate.compareTo(startDate) < 0
				|| tranDate.compareTo(endDate) > 0) {
			response.setProcCode(ProcCodeEnum.PROC_CODE_200W1004.getCode());
			return false;
		}*/
		
		return true;
	}

	/**
	 * 
	 * @param request
	 */
	private void subtractLimit(RcsTransLimitRequest request)
			throws GopayException {
		try {
			rcsModifyTransLimitService.subtractTranLimit(request);
		} catch (GopayException e) {
			try {
				rcsModifyTransLimitService.subtractTranLimit(request);
			} catch (GopayException e1) {
				throw e1;
			}
		}
	}

	/**
	 * 
	 * @param request
	 */
	private void addLimit(RcsTransLimitRequest request) throws GopayException {
		try {
			rcsModifyTransLimitService.addTranLimit(request);
		} catch (GopayException e) {
			try {
				rcsModifyTransLimitService.addTranLimit(request);
			} catch (GopayException e1) {
				throw e1;
			}
		}
	}

	/**
	 * 额度校验
	 * 
	 * @param request
	 * @param response
	 * @throws GopayException
	 */
	protected void checkLimit(RcsTransLimitRequest request,
			RcsTransLimitResponse response) throws GopayException {
		
		logger.info("开始风控额度校验：" + request.getGopayOrderId());

		TranLimitRes limitConf = request.getCustTranLimitConf();

		if(0 == request.getTotalNum()){
			return;
		}
		
		// 单笔额度校验
		BigDecimal onecLimit = limitConf.getOnceLimit();
		if (null != onecLimit && onecLimit.compareTo(new BigDecimal("0.00")) >= 0) {
			List<BigDecimal> tranAmts = request.getTranAmts();
			for(BigDecimal tranAmt : tranAmts){
				checkOnceLimit(tranAmt, onecLimit);
			}
		}

		// 累计额度统计信息
		RcsTransLimitStatistics limitStatistics = findRcsGAcctLimitStatistics(request);

		// 累计额度校验(校验总金额、总额度)
		checkLimitStatistics(request, response, limitStatistics);
	}

	/**
	 * 累计额度统计信息(校验总金额、总额度)
	 * 
	 * @param request
	 * @param response
	 * @param limitStatistics
	 * @throws GopayException
	 */
	protected void checkLimitStatistics(RcsTransLimitRequest request,
			RcsTransLimitResponse response,
			RcsTransLimitStatistics limitStatistics) throws GopayException {

		if (null == limitStatistics) {
			throw new GopayException(ProcCodeEnum.PROC_CODE_200F1002);
		}

		TranLimitRes limitConf = request.getCustTranLimitConf();
		BigDecimal totalAmt = request.getTotalAmt();
		int tranNum = request.getTotalNum();

		// 单日累计额度
		if (null != limitConf.getDayLimit()
				&& limitConf.getDayLimit().compareTo(new BigDecimal("0.00")) >= 0) {
			if (limitStatistics.getDayLimitStatcs().add(totalAmt)
					.compareTo(limitConf.getDayLimit()) == 1) {
				logger.error("单日累计额度超限：已发生累计金额="
						+ limitStatistics.getDayLimitStatcs() + ", 交易金额（批量总金额）="
						+ totalAmt + ", 单日累计额度=" + limitConf.getDayLimit());
                String error = String.format("订单号=%s 检测时间=%s 单日累计额度详情:已发生累计金额=%s 交易金额（批量总金额）=%s 单日累计额度=%s",
                        request.getGopayOrderId(),DateUtils.getCurrDate(),limitStatistics.getDayLimitStatcs(),totalAmt,limitConf.getDayLimit());
                rcsLogger.error(error);
				throw new GopayException(ProcCodeEnum.PROC_CODE_200E5006);
			}
		}

		// 单日累计次数
		if (limitConf.getDayTimes() >= 0) {
			if ((limitStatistics.getDayTimesStatcs() + tranNum) > limitConf.getDayTimes()) {
				logger.error("单日累计次数：已发生累计次数="
						+ limitStatistics.getDayTimesStatcs() + ", 单日累计次数=" + limitConf.getDayTimes()
						+ ", 当前交易次数（批量总次数）：" + tranNum);
                String error = String.format("订单号=%s 检测时间=%s 单日累计次数详情：已发生累计次数=%s 当前交易次数（批量总次数）=%s 单日累计次数=%s",
                        request.getGopayOrderId(),DateUtils.getCurrDate(),limitStatistics.getDayTimesStatcs(),tranNum,limitConf.getDayTimes());
                rcsLogger.error(error);
				throw new GopayException(ProcCodeEnum.PROC_CODE_200E5007);
			}
		}
	}

	/**
	 * 单笔额度校验
	 * 
	 * @param tranAmt
	 * @param onecLimit
	 * @throws GopayException
	 */
	protected void checkOnceLimit(BigDecimal tranAmt, BigDecimal onecLimit)
			throws GopayException {
		if (tranAmt.compareTo(onecLimit) == 1) {
			logger.error("单笔额度超限：交易金额=" + tranAmt + ", 单笔额度="
					+ onecLimit);
			throw new GopayException(ProcCodeEnum.PROC_CODE_200E5005);
		}
	}

	protected RcsTransLimitStatistics findRcsGAcctLimitStatistics(
			RcsTransLimitRequest request) {
		try {
			RcsGAcctLimitStatistics limitStatistics = rcsGAcctLimitStatisticsManager
					.getTransLimitStatistics(request.getCustId(),
							request.getAcctProd(), request.getIntTxnCd(),
							request.getTranDirection(), request.getTransDate());
			logger.info("累计额度统计信息：" + limitStatistics + ", gopayOrderId: " +request.getGopayOrderId());
			return limitStatistics;
		} catch (Exception e) {
			/**
			 * modified by zyt 日志中可能出现卡号地方做掩码显示
			 * 2017-3-22
			 */
			logger.error("获取客户累计额度统计信息异常：" + LoggerMaskUtils.maskString(request.toString()), e);
		}
		return null;
	}
}